#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h>  

#include "buffersocket.h"
#include "epollmanager.h"

int SetNonBlock(int sockfd)  
{  
	if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)  
	{  
		return -1;  
	}  
	return 0;  
}  
//return listenfd when success
int ServerSocketInit( const char * hostip, const int port )
{
	int ret = -1;
	struct sockaddr_in svraddr;
	
	int listenfd = socket( AF_INET, SOCK_STREAM, 0 );
	if ( listenfd >= 0 )
	{
		if ( SetNonBlock( listenfd ) == 0 )
		{
			bzero( &svraddr, sizeof(sockaddr_in) );
			svraddr.sin_family = AF_INET;
			inet_aton( hostip, &(svraddr.sin_addr) );
			svraddr.sin_port = htons( port );
			
			ret = bind( listenfd, (sockaddr *)&svraddr, sizeof(svraddr) );
			if ( 0 != ret )
				printf("bind error\n");
			else
			{
				ret = listen(listenfd,10);
				if ( 0 == ret )
				{
					ret = listenfd;
				}	
			}
		}
	}
	return ret;
}

int main( int argc, char * argv[] )
{
	if (argc<3)
	{
		printf("argv[1] host ip\n");
		printf("argv[2] port\n");
		exit(0);
	}
	//
	int listenfd, connfd, nfds, n;
	socklen_t clilen;
	char line[512] = {0};
	struct sockaddr_in cliaddr;
	struct epoll_event* pev;
	//
	listenfd = ServerSocketInit( argv[1], atoi( argv[2] ) );
	if ( listenfd < 0 )
		exit(1);
	else
		printf("listen fd %d\n",listenfd);
	//
	EpollManager mng( listenfd, 1024, 20 );
	mng.Init();
	
	printf("... ... running\n");
	for(;;)
	{
		nfds = mng.WaitEvents( 500 );
		printf("nfds %d\n",nfds);
		for (int i=0; i<nfds; ++i)
		{
			pev = mng.GetEventByPos( i );
			BufferSocket * pBufSocket = (BufferSocket *) pev->data.ptr;
			printf("event idx %d fd %d \n",i,pBufSocket->GetFd());
			if ( pBufSocket->GetFd()  == listenfd )
			{
				connfd = accept( listenfd, (sockaddr *)&cliaddr, &clilen );
				if ( connfd < 0 )
				{
					printf( "errno %d errmsg %s\n", errno, strerror(errno) );
					exit(1);
				}
				printf("accept a client, use fd[%d]\n",connfd);
				SetNonBlock(connfd);
				
				if ( mng.AddEvent( connfd, EPOLLIN, new BufferSocket(connfd) ) < 0 )
				{
					printf("error addevent,errno %d errmsg %s\n", errno, strerror(errno) );
				}
			}
			else if (pev->events & EPOLLIN )
			{
				//if ( (sockfd = events[i].data.fd) < 0) continue;
				pBufSocket = (BufferSocket * )pev->data.ptr;			
				pBufSocket->ClearReadBuffer();
				n = pBufSocket->ReadToBuffer();
				if ( n <= 0)
			   	{
					mng.DelEvent(pBufSocket->GetFd(), EPOLLOUT, pBufSocket);
					delete pBufSocket;
					pev->data.ptr = NULL;
					printf("read line'length[%d] server close fd[%d]\n",n,pBufSocket->GetFd() );
					if ( n<0 )
					{
						printf("errno %d errmsg %s\n", errno, strerror(errno) ); 
					}
				} 
				else //n>0
				{
					char * psbuf = pBufSocket->GetReadBuffer()->GetByteBuffer();
					int ilen = pBufSocket->GetReadBuffer()->GetLimit();
					pBufSocket->ClearWriteBuffer();
					pBufSocket->GetWriteBuffer()->Append( psbuf, ilen );
					if ( mng.Mod2W( pBufSocket->GetFd(), pBufSocket ) < 0 )
					{
						printf("mod2w error, errno %d errmsg %s\n", errno, strerror(errno) );
					}	
				}
			}
			else if(pev->events & EPOLLOUT)
			{
				BufferSocket * pBufSocket = (BufferSocket *) pev->data.ptr;
				pBufSocket->WriteFromBuffer();
				if ( mng.Mod2R( pBufSocket->GetFd(), pBufSocket ) < 0 ) 
				{
					printf("mod2r error, errno %d errmsg %s\n", errno, strerror(errno) );
				}
			}	
		}
	}
}

